﻿using System;
using System.ComponentModel;
using Service4u2.Common;

namespace Service4u2.Mock
{
    /// <summary>
    /// A simple base class for services that use a background worker to get their result.
    /// </summary>
    /// <typeparam name="TResultType">The type of the result type.</typeparam>
    public abstract class BaseBGWorkerService<TResultType> : IAsyncService<TResultType>
    {
        protected BackgroundWorker worker = new BackgroundWorker();

        #region IAsyncService<TResultType> Members

        /// <summary>
        /// Occurs when [got result].
        /// </summary>
        public event EventHandler<EventArgs<TResultType>> GotResult;

        /// <summary>
        /// Occurs when [got error].
        /// </summary>
        public event EventHandler<EventArgs<Exception>> GotError;

        #endregion

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseBGWorkerService&lt;TResultType&gt;"/> class.
        /// </summary>
        public BaseBGWorkerService()
        {
            worker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(worker_RunWorkerCompleted);
            worker.DoWork += new DoWorkEventHandler(worker_DoWork);
        }

        /// <summary>
        /// Starts the worker.
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        protected void StartWorker(object parameter)
        {
            worker.RunWorkerAsync(parameter);
        }

        /// <summary>
        /// Handles the DoWork event of the worker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.DoWorkEventArgs"/> instance containing the event data.</param>
        private void worker_DoWork(object sender, DoWorkEventArgs e)
        {
            try
            {
                e.Result = GetResult(e.Argument);
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// Gets the result; done on the background thread.
        /// </summary>
        /// <param name="parameter">The parameter.</param>
        /// <returns>The result desired.</returns>
        protected abstract TResultType GetResult(object parameter);

        /// <summary>
        /// Handles the RunWorkerCompleted event of the worker control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.ComponentModel.RunWorkerCompletedEventArgs"/> instance containing the event data.</param>
        private void worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            if (e.Error != null)
            {
                if (GotError != null)
                    GotError(this, new EventArgs<Exception>() { Argument = e.Error });
                
                return;
            }

            if (GotResult != null)
                GotResult(this, new EventArgs<TResultType>() { Argument = (TResultType)e.Result});
        }
    }
}
